package sk.fiit.vppj.eventmanager.graph;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLEncoder;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JDialog;
import javax.swing.SwingWorker;

/**
 * Class provides application with graph create from Google Graph API
 * 
 * @author Marek
 * 
 */
final class GoogleApi {

	private final static Logger log = Logger.getLogger( GoogleApi.class.getName() );
	private String url = null;
	private String root = "http://chart.apis.google.com/chart?"; // basic url to google api
	// private static final int MAX_CHART_RESOLUTION = 300000;
	// private static final int VALUES_MARGIN = 30;
	// private static final int VALUES_WIDTH = 1000;
	private final String chartMargin = "chbh=r,0.5,1.5";
	private ChartType chartType = null; // possible values lc, ls, lxy
	private final String chartBackground = "chf=bg,s,E1E1E1";
	private final String chartMeasure = "chxt=x,y";
	private final String chartDataColor = "chco=3D7930";
	private String chartTitle = null;

	public GoogleApi(List<Coordinate> data, String graphName, ChartType graphType) {
		this.chartTitle = graphName;
		this.chartType = graphType;
		this.url = parseData( data );
	}

	/**
	 * creates URL for google graph api from data
	 * @param data
	 * @return
	 */
	private String parseData(List<Coordinate> data) {

		StringBuilder tmpUrl = new StringBuilder( 600 );
		tmpUrl.append( root );
		tmpUrl.append( "&" + chartBackground );
		tmpUrl.append( "&" + getChartSize( data ) );
		tmpUrl.append( "&" + getChartType( chartType ) );
		tmpUrl.append( "&" + chartMeasure );
		tmpUrl.append( "&" + chartMargin );

		tmpUrl.append( "&" + getChxr( data ) );
		tmpUrl.append( "&" + getChxl( data ) );
		tmpUrl.append( "&" + chartDataColor );
		tmpUrl.append( "&" + getChds( data ) );
		tmpUrl.append( "&" + getChd( data ) );
		tmpUrl.append( "&" + getChartTitle( chartTitle ) );
		return tmpUrl.toString();
	}

	private String getChartType(ChartType chartType) {
		if( chartType.equals( ChartType.VERTICAL_BAR ) ) {
			return "cht=bvg";
		}
		else if( chartType.equals( ChartType.LINE_CHART_BASIC ) ) {
			return "cht=lc";
		}
		return "cht=bvg";
	}

	private String getChartSize(List<Coordinate> data) {
		// TODO correct implementation
		return "chs=1000x250";
	}

	private String getChartTitle(String chartTitle) {
		return "chtt=" + chartTitle;
	}

	private String getChxl(List<Coordinate> data) {
		StringBuilder xLabel = new StringBuilder( 300 );
		xLabel.append( "chxl=0:" );
		try {
			for ( Coordinate coord : data ) {
				xLabel.append( "|" );
				xLabel.append( URLEncoder.encode( coord.getX(), "UTF-8" ) ); // formating url to correct state
			}
		}
		catch ( UnsupportedEncodingException e ) {
			xLabel.append( "0" );
			e.printStackTrace();
		}
		return xLabel.toString();
	}

	private String getChd(List<Coordinate> data) {
		StringBuilder yData = new StringBuilder( 300 );
		yData.append( "chd=t:" );
		for ( Coordinate coord : data ) {
			yData.append( coord.getY() );
			yData.append( "," );
		}
		return yData.toString().substring( 0, yData.toString().length() - 1 );
	}

	private String getChxr(List<Coordinate> data) {
		StringBuilder yData = new StringBuilder( 10 );
		int maxValue = 0;
		yData.append( "chxr=1,0," );
		for ( Coordinate coord : data ) {
			if( maxValue < coord.getY() ) {
				maxValue = coord.getY();
			}
		}
		yData.append( maxValue );
		return yData.toString();

	}

	private String getChds(List<Coordinate> data) {
		StringBuilder yData = new StringBuilder( 10 );
		int maxValue = 0;
		yData.append( "chds=0," );
		for ( Coordinate coord : data ) {
			if( maxValue < coord.getY() ) {
				maxValue = coord.getY();
			}
		}
		yData.append( maxValue );
		return yData.toString();

	}

	private String getUrl() {
		return this.url;
	}

	/**
	 * Tries to connect to server and recieve graph from it. It is multithreaded.
	 * 
	 * @return Graph
	 */
	public ImageIcon getGraphIcon() {
		SwingWorker<ImageIcon, ImageIcon> w = new SwingWorker<ImageIcon, ImageIcon>() {

			@Override
			protected ImageIcon doInBackground() throws Exception {

				try {
					//donwloads graph from google website
					return new ImageIcon( ImageIO.read( new URL( getUrl() ) ) );
				}
				catch ( MalformedURLException e ) {
					log.log( Level.WARNING, "Url to google api is not well-formed!", e );
					e.printStackTrace();
				}
				catch ( IOException e ) {
					log.log( Level.INFO, "Google graph api returned invalid image!" );
					e.printStackTrace();
				}
				return null;
			}

		};
		w.execute();
		final JDialog dialog = new JDialog();
		dialog.setVisible( true );
		w.addPropertyChangeListener( new PropertyChangeListener() {

			@Override
			public void propertyChange(PropertyChangeEvent event) {
				if( "state".equals( event.getPropertyName() ) && SwingWorker.StateValue.DONE == event.getNewValue() ) {
					dialog.setVisible( false );
					dialog.dispose();

				}
			}
		} );
		try {

			return w.get();
		}
		catch ( InterruptedException e ) {
			log.log( Level.INFO, "Process of getting graph from google graph api was interrupted!", e );
			e.printStackTrace();
		}
		catch ( ExecutionException e ) {
			log.log( Level.INFO, "Process of getting graph from google graph api failed!", e );
			e.printStackTrace();
		}
		return null;

	}
}
